//
// Created by Luhang on 2023/10/13/013.
//

#ifndef LOGPROJECT_LOGGER_H
#define LOGPROJECT_LOGGER_H

#include "util.hpp"
#include "level.hpp"
#include "message.hpp"
#include "formatter.hpp"
#include "sink.hpp"
//#include "looper.h"
#include <vector>
#include <list>
#include <atomic>
#include <unordered_map>
#include <cstdarg>
#include <type_traits>
#include <functional>
#include <cstdio>
#include <cstdlib>

namespace LuLog{
    class SyncLogger;
    class Logger{
    public:
        //日志器类型
        enum class Type{
            LOGGER_SYNC = 0,
            LOGGER_ASYNC
        };
        
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &name, 
                Formatter::ptr formatter,
                std::vector<LogSink::ptr> &sinks,
                LogLevel::level level = LogLevel::level::DEBUG):
                _name(name), _formatter(formatter), _level(level),
                 _sinks(sinks.begin(), sinks.end()){

                 }
        std::string loggerName(){
            return _name;
        }
        LogLevel::level loggerLevel(){
            return _level;
        }
        //通过传入的参数构造一个日志消息对象
        void debug(const char *file, size_t line, const char *fmt, ...){
            if(!shouldLog(LogLevel::level::DEBUG))
                return;
            va_list al;
            va_start(al, fmt);
            log(LogLevel::level::DEBUG, file, line, fmt, al);
            va_end(al);
        }
        void info(const char *file, size_t line, const char *fmt, ...) {
            if (!shouldLog(LogLevel::level::INFO)) return ;
            va_list al;
            va_start(al, fmt);
            log(LogLevel::level::INFO, file, line, fmt, al);
            va_end(al);
        }
        void warn(const char *file, size_t line, const char *fmt, ...) {
            if (!shouldLog(LogLevel::level::WARN)) return ;
            va_list al;
            va_start(al, fmt);
            log(LogLevel::level::WARN, file, line, fmt, al);
            va_end(al);
        }
        void error(const char *file, size_t line, const char *fmt, ...) {
            if (!shouldLog(LogLevel::level::ERROR)) return ;
            va_list al;
            va_start(al, fmt);
            log(LogLevel::level::ERROR, file, line, fmt, al);
            va_end(al);
        }
        void fatal(const char *file, size_t line, const char *fmt, ...) {
            if (!shouldLog(LogLevel::level::FATAL)) return ;
            va_list al;
            va_start(al, fmt);
            log(LogLevel::level::FATAL, file, line, fmt, al);
            va_end(al);
        }
    protected:
        bool shouldLog(LogLevel::level level){
            return level >= _level;
        }
        //对传入的参数构造日志消息对象，格式化，落地
        void log(LogLevel::level level, const char *file, size_t line, const char *fmt, va_list al){
            char *buf;
            std::string msg;
            int len = vasprintf(&buf, fmt, al);
            if(len < 0)
                msg = "格式化日志消息失败!!!";
            else{
                msg.assign(buf, len);
                free(buf);
            } 
            //构造LogMsg对象
            LogMsg lm(level, _name, file, line, std::move(msg));
            //对消息进行格式化
            std::stringstream ss;
            _formatter->format(ss, lm);
            //进行日志落地
            logIt(ss.str());
        }
        virtual void logIt(const std::string &msg) = 0;
    protected:
        std::mutex _mutex;
        std::string _name;
        Formatter::ptr _formatter;
        std::atomic<LogLevel::level> _level;
        std::vector<LogSink::ptr> _sinks;

    public:
        //抽象出一个日志器建造者类，完成日志器所需零部件的构建
        class Builder{
        public:
            using ptr = std::shared_ptr<Builder>;
            Builder():_level(LogLevel::level::DEBUG),
                    _loggerType(Logger::Type::LOGGER_SYNC){}
            void buildLoggerName(const std::string &name){
                _loggerName = name;
            }
            void buildLoggerLevel(LogLevel::level level){
                _level = level;
            }
            void buildLoggerType(Logger::Type type){
                _loggerType = type;
            }
            void buildFormatter(const std::string pattern){
                _formatter = std::make_shared<Formatter>(pattern);
            }
            void buildFormatter(const Formatter::ptr &formatter){
                _formatter = formatter;
            }
            template<typename SinkType, typename ...Args>
            void buildSink(Args &&...args){
                auto sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
                _sinks.push_back(sink);
            }
            virtual Logger::ptr build() = 0;
        protected:
            Logger::Type _loggerType;
            std::string _loggerName;
            LogLevel::level _level;
            Formatter::ptr _formatter;
            std::vector<LogSink::ptr> _sinks;
        };
    };

    class SyncLogger: public Logger{
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(const std::string &name, 
                Formatter::ptr formatter,
                std::vector<LogSink::ptr> &sinks,
                LogLevel::level level = LogLevel::level::DEBUG):
                Logger(name, formatter, sinks, level){
            std::cout << LogLevel::toString(level) << " 同步日志器: " << name << "创建成功...\n";
                }
    private:
        void logIt(const std::string &msg) override{
            std::unique_lock<std::mutex> lock(_mutex);
            if(_sinks.empty())
                return;
            for(auto &it : _sinks)
                it->log(msg.c_str(), msg.size());
        }
    };

    //局部日志器建造者
    class LocalLoggerBuilder: public Logger::Builder{
    public:
        Logger::ptr build() override{
            if (_loggerName.empty()) {
                std::cout << "日志器名称不能为空！！";
                abort();
            }
            if (_formatter.get() == nullptr) {
                std::cout << "当前日志器：" << _loggerName << " 未检测到日志格式，默认设置为[ %d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n ]!\n";
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty()) {
                std::cout << "当前日志器：" << _loggerName << " 未检测到落地方向，默认设置为标准输出!\n";
                _sinks.push_back(std::make_shared<StdoutSink>());
            }
            Logger::ptr lp;
            if (_loggerType == Logger::Type::LOGGER_ASYNC) {
                //lp = std::make_shared<AsyncLogger>(_loggerName, _formatter, _sinks, _level);
            }else {
                lp = std::make_shared<SyncLogger>(_loggerName, _formatter, _sinks, _level);
            }
            return lp;
        }
    };
}
#endif //LOGPROJECT_LOGGER_H
